package com.deepseek.project.tool;

import com.deepseek.project.constant.Constants;
import com.deepseek.project.service.ITalkInfoService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * author：hulei
 * DeepSeekOnlineTool,请求线上DeepSeek接口的工具,适用于自己本地没有硬件条件部署的
 */
@Setter
@Getter
@Slf4j
@Component
public class DeepSeekOnlineTool extends AbstractChatTool {

    // 替换为线上 API 的实际地址,这个地址也可能会失效，访问不了报404错误时,请从官网查找URL
    private static final String URL = "https://api.deepseek.com/chat/completions";
    // 替换为你自己的 API 密钥(DeepSeek的API密钥,赠送的失效可能需要充值，否则报错402)
    private static final String API_KEY = "*********************";
    /**
     * 这个最新绑定的是R1模型
     */
    private static final String MODEL = "deepseek-reasoner";

    public DeepSeekOnlineTool(ITalkInfoService italkInfoService, List<Map<String, String>> conversationHistory) {
        super(italkInfoService, conversationHistory);
    }

    private boolean thinkSymbol = false;

    @Override
    protected Request buildRequest() {
        // 构建请求体的 JSON 数据
        MediaType JSON = MediaType.get("application/json; charset=utf-8");
        Map<String, Object> data = new HashMap<>();
        data.put("model", MODEL);
        data.put("messages", Collections.unmodifiableList(getConversationHistory()));
        data.put("stream", true);

        RequestBody body = RequestBody.create(gson.toJson(data), JSON);

        return new Request.Builder()
                .url(URL)
                .addHeader("Authorization", "Bearer " + API_KEY)
                .post(body)
                .build();
    }

    /**
     * 请求DeepSeek的流式响应
     */
    @Override
    public void requestDeepSeekMessage(WebSocketSession session, String talkInfoId) {
        Request request = buildRequest();
        // 发起异步请求并处理流式响应
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                log.error("请求失败: {}", e.getMessage());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) {
                try (ResponseBody responseBody = response.body()) {
                    if (!response.isSuccessful()) {
                        throw new IOException("请求失败，状态码: " + response.code());
                    }
                    if (responseBody == null) {
                        throw new IOException("响应体为空");
                    }
                    processStreamResponse(responseBody, session, talkInfoId);
                    // 发送流式响应结束标记
                    sendEndMarker(session);
                    thinkSymbol = false;
                } catch (IOException e) {
                    log.error("处理响应时出错: {}", e.getMessage());
                }
            }
        });
    }

    public void processStreamResponse(ResponseBody responseBody, WebSocketSession session, String talkInfoId) throws IOException {
        // 使用 BufferedReader 逐行读取流式响应
        BufferedReader reader = new BufferedReader(new InputStreamReader(responseBody.byteStream(), StandardCharsets.UTF_8));
        String line;
        while (!stopSending && (line = reader.readLine()) != null) {
            if (line.startsWith("data: ")) {
                String data = line.substring(6);
                if (!data.equals("[DONE]")) {
                    log.info("解析前的: {}", data);
                    String content = getContent(data);
                    Map<String, String> assistantMessageMap = Map.of("role", "assistant", "content", content == null ? "" : content);
                    synchronized (conversationHistory) {
                        conversationHistory.add(assistantMessageMap);
                    }
                    if (!talkInfoId.startsWith(Constants.TEMP_TALK_INFO_ID_PREFIX)) {
                        addMessageToCache(assistantMessageMap, talkInfoId);
                    }
                    if (!stopSending) {
                        session.sendMessage(new TextMessage(content == null ? "" : content));
                    }
                }
            }
        }
    }

    /**
     * 解析JSON获取流式响应的内容,这里的处理逻辑可能会让读者朋友产生困惑,因为笔者是要区分大模型返回的逻辑推理部分和真正的答案部分，逻辑推理部分要用<thing></thing>
     * 标签包住，便于前端根据这个区分渲染不同的样式,线上的deepseek回答的格式可能会在未来发生变化，甚至包括笔者上面使用的URL,只能自行判断修改了
     */
    public String getContent(String messageJson) {
        ObjectMapper objectMapper = new ObjectMapper();
        String returnContent = null;
        try {
            JsonNode rootNode = objectMapper.readTree(messageJson);
            JsonNode choicesNode = rootNode.get("choices");
            if (choicesNode.isArray()) {
                for (JsonNode choice : choicesNode) {
                    JsonNode deltaNode = choice.get("delta");
                    if (deltaNode != null) {
                        JsonNode contentNode = deltaNode.get("content");
                        String content = contentNode != null && !contentNode.isNull() ? contentNode.asText() : null;

                        JsonNode reasoningContentNode = deltaNode.get("reasoning_content");
                        String reasoningContent = reasoningContentNode != null && !reasoningContentNode.isNull() ? reasoningContentNode.asText() : null;
                        // 如果contentNode为null,则返回"<think>",因为这是思考部分的逻辑
                        if (content == null && "".equals(reasoningContent)) {
                            thinkSymbol = true;
                            returnContent = "<think>";
                            break;
                        } else if (content == null && reasoningContent != null) {
                            // 如果reasoningContent为null，则返回"</think>\n" + contentNode.asText()，因为这是正常回答的逻辑内容
                            returnContent = reasoningContent;
                            break;
                        } else if (content != null && reasoningContent == null) {
                            if (thinkSymbol) {
                                returnContent = "</think>\n" + content;
                                thinkSymbol = false;
                            } else {
                                returnContent = content;
                            }
                            break;
                        }
                    }
                }
            }
        } catch (IOException e) {
            log.error("解析 JSON 数据时出错: {}", e.getMessage());
        }
        return returnContent;
    }

}
